package com.meiyuetao.myt.finance.service;

import java.util.Date;
import java.util.List;
import java.util.Map;

import lab.s2jh.bpm.service.ActivitiService;
import lab.s2jh.core.dao.BaseDao;
import lab.s2jh.core.service.BaseService;
import lab.s2jh.core.service.Validation;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.Lists;
import com.meiyuetao.myt.core.constant.VoucherStateEnum;
import com.meiyuetao.myt.core.constant.VoucherTypeEnum;
import com.meiyuetao.myt.finance.dao.TradeReceiptDao;
import com.meiyuetao.myt.finance.entity.AccountInOut;
import com.meiyuetao.myt.finance.entity.TradeReceipt;
import com.meiyuetao.myt.finance.entity.TradeReceiptDetail;
import com.meiyuetao.myt.purchase.service.PurchaseOrderService;
import com.meiyuetao.myt.purchase.service.PurchaseReceiptService;
import com.meiyuetao.myt.purchase.service.PurchaseReturnOrderService;
import com.meiyuetao.myt.sale.service.BoxOrderService;
import com.meiyuetao.myt.sale.service.SaleDeliveryService;
import com.meiyuetao.myt.sale.service.SaleReturnApplyService;
import com.meiyuetao.myt.sale.service.SaleReturnService;
import com.meiyuetao.myt.stock.service.CommodityStockMoveService;
import com.meiyuetao.myt.stock.service.CommodityStockService;

@Service
@Transactional
public class TradeReceiptService extends BaseService<TradeReceipt, Long> {

    @Autowired
    private TradeReceiptDao tradeReceiptDao;
    @Autowired
    private AccountInOutService accountInOutService;
    @Autowired(required = false)
    private ActivitiService activitiService;
    @Autowired
    private PurchaseOrderService purchaseOrderService;
    @Autowired
    private PurchaseReceiptService purchaseReceiptService;
    @Autowired
    private BoxOrderService boxOrderService;
    @Autowired
    private SaleDeliveryService saleDeliveryService;
    @Autowired
    private CommodityStockMoveService commodityStockMoveService;
    @Autowired
    private CommodityStockService commodityStockService;
    @Autowired
    private PurchaseReturnOrderService purchaseReturnOrderService;
    @Autowired
    private SaleReturnApplyService saleReturnApplyService;
    @Autowired
    private SaleReturnService saleReturnService;

    @Override
    protected BaseDao<TradeReceipt, Long> getEntityDao() {
        return tradeReceiptDao;
    }

    public void bpmCreate(TradeReceipt entity, Map<String, Object> variables) {
        tradeReceiptDao.save(entity);
        activitiService.startProcessInstanceByKey("BPM_PAYMENT_APPLY", entity);

    }

    public void bpmUpdate(TradeReceipt entity, String taskId, Map<String, Object> variables) {
        tradeReceiptDao.save(entity);
        activitiService.completeTask(taskId, variables);
    }

    public void create(TradeReceipt entity) {
        String bizVoucher = entity.getBizVoucher();
        VoucherTypeEnum bizVoucherType = entity.getBizVoucherType();
        if (StringUtils.isNotBlank(bizVoucher)) {
            if (bizVoucherType != null) {
                switch (bizVoucherType) {
                case JHD:// 采购订单 PurchaseOrderService
                    Validation.isTrue(purchaseOrderService.findByProperty("voucher", bizVoucher) != null, "未在 采购订单 中找到 业务凭证号");
                    break;
                case JH:// 采购(入库)单 PurchaseReceiptService
                    Validation.isTrue(purchaseReceiptService.findByProperty("voucher", bizVoucher) != null, "未在 采购(入库)单 中找到 业务凭证号");
                    break;
                case XSD:// 销售订单 BoxOrderService
                    Validation.isTrue(boxOrderService.findByProperty("orderSeq", bizVoucher) != null, "未在 销售订单 中找到 业务凭证号");
                    break;
                case XS:// 销售单 SaleDeliveryService
                    Validation.isTrue(saleDeliveryService.findByProperty("voucher", bizVoucher) != null, "未在 销售单 中找到 业务凭证号");
                    break;
                case DH:// 调拨单 CommodityStockMoveService
                    Validation.isTrue(commodityStockMoveService.findByProperty("voucher", bizVoucher) != null, "未在 调拨单 中找到 业务凭证号");
                    break;
                case FKD:// 付款单 this
                    Validation.isTrue(this.findByProperty("voucher", bizVoucher) != null, "未在 付款单 中找到 业务凭证号");
                    break;
                case CGTH:// 采购退货
                    Validation.isTrue(purchaseReturnOrderService.findByProperty("voucher", bizVoucher) != null, "未在 采购退货 中找到 业务凭证号");
                    break;
                case THSQ:// 退货申请
                    Validation.isTrue(saleReturnApplyService.findByProperty("voucher", bizVoucher) != null, "未在 退货申请 中找到 业务凭证号");
                    break;
                /*
                 * case TH://退货 SaleReturnService
                 * Validation.isTrue(saleReturnService.findByProperty("voucher",
                 * bizVoucher)!=null, "未在 退货 中找到 业务凭证号"); break; case SKD://收款单
                 * this Validation.isTrue(this.findByProperty("voucher",
                 * bizVoucher)!=null, "未在 收款单 中找到 业务凭证号"); break;
                 */
                default:
                    break;
                }
            } else {
                Validation.isTrue(false, "请选择 业务凭证类型");
            }
        }
        entity.setLastOperationSummary(entity.buildLastOperationSummary("创建"));
        entity.setActiveTaskName("NONE");
        entity.setPayTime(new Date());
        saveDetails(entity);
        tradeReceiptDao.save(entity);
    }

    private AccountInOut buildDefaultAccountInOut(TradeReceipt entity) {
        AccountInOut accountInOut = new AccountInOut();
        accountInOut.setVoucher(entity.getVoucher());
        accountInOut.setVoucherType(entity.getReceiptType());
        accountInOut.setPostingDate(entity.getVoucherDate());
        return accountInOut;
    }

    private AccountInOut buildRedAccountInOut(TradeReceipt entity) {
        AccountInOut accountInOut = new AccountInOut();
        accountInOut.setVoucher(entity.getVoucher());
        accountInOut.setVoucherType(entity.getReceiptType());
        accountInOut.setPostingDate(entity.getVoucherDate());
        return accountInOut;
    }

    private void saveDetails(TradeReceipt entity) {
        // 付款单付款记账
        List<AccountInOut> accountInOuts = Lists.newArrayList();

        // 借：用户选择结算科目，如2202=应付账款
        AccountInOut accountInOut1 = buildDefaultAccountInOut(entity);
        accountInOut1.setAccountSubject(entity.getAccountSubject());
        accountInOut1.setAccountSummary(entity.getAccountSummary());
        accountInOut1.setAmount(entity.getTotalAmount());
        accountInOut1.setAccountDirection(true);
        accountInOut1.setBizTradeUnit(entity.getBizTradeUnit());
        accountInOuts.add(accountInOut1);

        List<TradeReceiptDetail> tradeReceiptDetails = entity.getTradeReceiptDetails();
        for (TradeReceiptDetail tradeReceiptDetail : tradeReceiptDetails) {
            // 贷：用户选择的出账科目，如现金/银行存款等减少
            AccountInOut accountInOut = buildDefaultAccountInOut(entity);
            accountInOut.setAccountSubject(tradeReceiptDetail.getAccountSubject());
            accountInOut.setAccountSummary(entity.getAccountSummary());
            accountInOut.setAmount(tradeReceiptDetail.getAmount());
            accountInOut.setAccountDirection(false);
            accountInOuts.add(accountInOut);
        }

        accountInOutService.saveBalance(accountInOuts);
    }

    public void bpmPay(TradeReceipt entity, String taskId) {
        saveDetails(entity);
        tradeReceiptDao.save(entity);
        activitiService.completeTask(taskId, null);
    }

    /**
     * 未付款红冲（移除工作流、克隆创建红冲对象）
     * 
     * @param entity
     * @return
     */
    public TradeReceipt chargeAgainstSimple(TradeReceipt entity) {
        Validation.isTrue(entity.getRedwordDate() == null, "单据已经红冲");
        // 移除工作流实例
        activitiService.deleteProcessInstanceByEntity(entity);
        entity.setRedwordDate(new Date());
        entity.setVoucherState(VoucherStateEnum.REDW);
        entity.setLastOperationSummary(entity.buildLastOperationSummary("红冲"));
        tradeReceiptDao.save(entity);

        // 克隆创建红冲对象，只复制主对象，明细行项数据不复制
        TradeReceipt redwordTarget = new TradeReceipt();
        String[] copyIgnoreProperties = ArrayUtils.addAll(entity.retriveCommonProperties(), new String[] { "tradeReceiptDetails", "voucher", "voucherDate" });
        BeanUtils.copyProperties(entity, redwordTarget, copyIgnoreProperties);
        redwordTarget.setVoucherDate(new Date());
        redwordTarget.setVoucherState(VoucherStateEnum.REDW);
        redwordTarget.setVoucher("R" + entity.getVoucher());
        tradeReceiptDao.save(redwordTarget);
        return redwordTarget;
    }

    /**
     * 付款单红冲
     * 
     * @param entity
     */
    public void chargeAgainstPayment(TradeReceipt entity) {
        TradeReceipt redwordTarget = chargeAgainstSimple(entity);

        // 资产类“借”增“贷”减 负债类 “借”减“贷”增
        // 付款单付款记账
        List<AccountInOut> accountInOuts = Lists.newArrayList();

        // 贷： 资产类 1122应收账款 入
        AccountInOut accountInOut1 = buildRedAccountInOut(redwordTarget);
        accountInOut1.setAccountSubjectCode("1122");
        accountInOut1.setAccountSummary("付款单红冲应收账款");
        accountInOut1.setAmount(entity.getTotalAmount());
        accountInOut1.setAccountDirection(false);
        accountInOut1.setBizTradeUnit(entity.getBizTradeUnit());
        accountInOuts.add(accountInOut1);

        List<TradeReceiptDetail> tradeReceiptDetails = entity.getTradeReceiptDetails();
        for (TradeReceiptDetail tradeReceiptDetail : tradeReceiptDetails) {
            // 借：负债类 2202应付账款 出
            AccountInOut accountInOut = buildRedAccountInOut(redwordTarget);
            accountInOut.setAccountSubjectCode("2202");
            accountInOut.setAccountSummary("付款单红冲应付账款");
            accountInOut.setAmount(tradeReceiptDetail.getAmount());
            accountInOut.setAccountDirection(true);
            accountInOuts.add(accountInOut);
        }

        accountInOutService.saveBalance(accountInOuts);
    }

    /**
     * 收款单红冲
     * 
     * @param entity
     */
    public void chargeAgainstReceivable(TradeReceipt entity) {
        TradeReceipt redwordTarget = chargeAgainstSimple(entity);

        // 付款单付款记账
        List<AccountInOut> accountInOuts = Lists.newArrayList();

        // 借：用户选择结算科目，如2202=应付账款
        AccountInOut accountInOut1 = buildRedAccountInOut(redwordTarget);
        accountInOut1.setAccountSubject(entity.getAccountSubject());
        accountInOut1.setAccountSummary("收款单红冲应付账款");
        accountInOut1.setAmount(entity.getTotalAmount());
        accountInOut1.setAccountDirection(true);
        accountInOut1.setBizTradeUnit(entity.getBizTradeUnit());
        accountInOuts.add(accountInOut1);

        List<TradeReceiptDetail> tradeReceiptDetails = entity.getTradeReceiptDetails();
        for (TradeReceiptDetail tradeReceiptDetail : tradeReceiptDetails) {
            // 贷：用户选择的出账科目，如现金/银行存款等减少
            AccountInOut accountInOut = buildRedAccountInOut(redwordTarget);
            accountInOut.setAccountSubject(tradeReceiptDetail.getAccountSubject());
            accountInOut.setAccountSummary("收款单红冲应收账款");
            accountInOut.setAmount(tradeReceiptDetail.getAmount());
            accountInOut.setAccountDirection(false);
            accountInOuts.add(accountInOut);
        }

        accountInOutService.saveBalance(accountInOuts);
    }

}
